/*
 *  FSDefineButton2.h
 *  Transform SWF
 * 
 * Copyright (c) 2001-2004 Flagstone Software Ltd.. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution.
 *  * Neither the name of Flagstone Software Ltd. nor the names of its contributors 
 *    may be used to endorse or promote products derived from this software 
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __FSDefineButton2_h__
#define __FSDefineButton2_h__

#include "FSDefineObject.h"

#include "FSVector.h"
#include "FSButton.h"
#include "FSButtonEvent.h"

#ifdef WIN32
#ifdef _WINDLL
DLL_TEMPLATE template class DLL_DECL transform::FSVector<transform::FSButton>;
DLL_TEMPLATE template class DLL_DECL transform::FSVector<transform::FSButtonEvent>;
#endif // _WINDLL
#endif // WIN32

namespace transform
{
/**
 * %FSDefineButton2 defines the appearance and actions of push and menu buttons. 
 * 
<p>It provides a more sophisticated model for creating buttons:</p>

<ul>
<li>Two types of button are supported, <B>Push</B> and <B>Menu</B>.</li>
<li>The number of events that a button can respond to is increased.</li>
<li>Actions can be executed for any button event.</li>
</ul>

<p>Push and Menu buttons behave slightly differently in tracking mouse movements when the button is clicked. A Push button 'captures' the mouse so if the cursor is dragged outside of the active area of the button and the mouse click is released then the Release Outside event is still sent to the button. A Menu button does not 'capture' the mouse so if the cursor is dragged out of the active area the button returns to its 'inactive' state.</p>

<table class="datasheet">

<tr><th align="left" colspan="2">Attributes</th></tr>

<tr>
<td><a name="FSDefineButton2_0">type</a></td>
<td>Identifies the data structure when it is encoded. Read-only.</td>
</tr>

<tr>
<td><a name="FSDefineButton2_1">identifier</a></td>
<td>An unique identifier for this object in the range 1..65535.</td>
</tr>

<tr>
<td><a name="FSDefineButton2_2">buttonType</a></td>
<td>Whether the button is a Push button or a Menu button.</td>
</tr>

<tr>
<td><a name="FSDefineButton2_3">buttonRecords</a></td>
<td>An array of FSButton objects that describe the appearance of the button in each of its states.</td>
</tr>

<tr>
<td><a name="FSDefineButton2_4">buttonEvents</a></td>
<td>An array of FSButtonEvent objects that define the actions that are executed for each type of button event.</td>
</tr>

<tr><td><a name="FSDefineButton2_5">encodedEvents</a></td>
<td>An array of bytes containing encoded button events can also be set. The encoded objects are typically generated by the parser in the Translate framework. The buttonEvents array and encodedEvents cannot both be valid at the same time. Accessor methods used to set either of the attributes will set the other to null.</td>
</tr>

</table>

<p>An FSDefineButton2 object must contain at least one FSButton object. If more than one button record is defined for a given button state then each shape will be displayed by the button. The order in which the shapes are displayed is determined by the layer assigned to each button record.</p>

<p>Each FSButton object can contain an FSColorTransform object which can be used to change the colour of the shape being displayed without changing the original definition.</p>

<p>Actions do not need to be specified for every button event. Indeed actions do not need to be specified at all.</p>

<h1 class="datasheet">Examples</h1>

1. Define a button that highlights itself when the mouse is move over it and actions are executed when the button is clicked.

<pre>
FSDefineShape* upShape = new FSDefineShape(movie.newIdentifier(), bounds, fillStyles, lineStyles, shape1);
FSDefineShape* overShape = new FSDefineShape(movie.newIdentifier(), bounds, fillStyles, lineStyles, shape2);
FSDefineShape* downShape = new FSDefineShape(movie.newIdentifier(), bounds, fillStyles, lineStyles, shape3);

FSVector&lt;FSButton&gt; records;
FSVector&lt;FSButtonEvent&gt; events;

records.push_back(FSButtonRecord(FSButton::Up, upShape-&gt;getIdentifier(), 1));
records.push_back(FSButtonRecord(FSButton::Over, overShape-&gt;getIdentifier(), 2));
records.push_back(FSButtonRecord(FSButton::Down, downShape-&gt;getIdentifier(), 3));

FSVector&lt;FSActionObject*&gt; actions;

actions.push_back(action);
actions.push_back(action);
actions.push_back(action);

events.push_back(FSButtonEvent(FSButtonEvent::Press, actions));

FSDefineButton2* button = new FSDefineButton2(movie.newIdentifier(), FSDefineButton2::Push, records, events);
</pre>


<h1 class="datasheet">History</h1>

<p>The FSDefineButton2 class represents the DefineButton2 structure from the Macromedia Flash (SWF) File Format Specification. It was introduced in Flash 3.</p>

 */  
    class DLL_DECL FSDefineButton2 : public FSDefineObject
    {
public:
        /** Defines the two type of button supported by the FSDefineButton2 class */
        enum buttonType { Push = 0, Menu = 1 };

        FSDefineButton2(FSInputStream* aStream);
    
        /** Constructs an FSDefineButton2 object, specifying the unique identifier, the type of button to be created, the button records that describe the button's appearance and the actions that are performed in response to each button event.
        
            @param anIdentifier a unique identifier for this button.
            @param buttonType the type of button - push or menu.
            @param buttonRecordArray an array of FSButton objects.
            @param buttonEventArray and array of FSButtonEvent objects.
            */
        FSDefineButton2(int anIdentifier, int buttonType, const FSVector<FSButton>& buttonRecordArray, const FSVector<FSButtonEvent>& buttonEventArray) 
            : FSDefineObject(DefineButton2, anIdentifier)
            , buttonType(buttonType)
            , buttonRecords(buttonRecordArray)
            , buttonEvents(buttonEventArray)
            , encodedEvents(0)
            , encodedLength(0)
        {}

        /** 
         * Constructs an FSDefineButton object, specifying the unique identifier, the 
         * type of button to be created, the button records that describe the button's 
         * appearance and the encoded actions that are performed in response to each 
         * button event.
         * 
         * @param anIdentifier a unique identifier for this button.
         * @param buttonType the type of button - push or menu.
         * @param buttonRecordArray an array of FSButton objects.
         * @param bytes an array containing the encoded FSButtonEvent objects.
         * @param size the number of bytes in the encoded events.
         */
        FSDefineButton2(int anIdentifier, int buttonType, const FSVector<FSButton>& buttonRecordArray, byte* bytes, size_t size) 
            : FSDefineObject(DefineButton2, anIdentifier)
            , buttonType(buttonType)
            , buttonRecords(buttonRecordArray)
            , buttonEvents()
            , encodedEvents(bytes)
            , encodedLength(size)
        {}

        FSDefineButton2* clone() const { return new FSDefineButton2(*this); }

        const char* className() const;

        /** Adds a button record object to the array of button records.

            @param aButtonRecord a button record.
            */
        void add(const FSButton& aButtonRecord) { buttonRecords.push_back(aButtonRecord); }

        /** Adds all the button record objects to the end of the array of button records.

            @param anArray an array of FSButtons.
            */
        void add(const FSVector<FSButton>& anArray);

        /** Adds a button event object to the array of button events.

            @param aButtonEvent a button event.
            */
        void add(const FSButtonEvent& aButtonEvent);

        /** Adds all the button event objects to the end of the array of button events.

            @param anArray an array of FSButtonEvents.
            */
        void add(const FSVector<FSButtonEvent>& anArray);

        /** Gets the button type - push or menu.

            @return the type of button.
            */
        int getButtonType() const { return buttonType; }

        /** Gets the array of button records defined for this button.

            @return the array of button records.
            */
        FSVector<FSButton>& getButtonRecords() { return buttonRecords; }

        /** Gets the array of button records defined for this button.

            @return the array of button events.
            */
        FSVector<FSButtonEvent>& getButtonEvents() { return buttonEvents; }

        /** Sets the button type.

            @param aType the type of button - push or menu.
            */
        void setButtonType(int aType) { buttonType = aType; }

        /** Sets the array of button records defined for this button.

            @param anArray an array of FSButton objects.
            */
        void setButtonRecords(const FSVector<FSButton>& anArray) { buttonRecords = anArray; }

        /** Sets the array of button events defined for this button.

            @param anArray an array of FSButtonEvent objects.
            */
        void setButtonEvents(const FSVector<FSButtonEvent>& anArray) { buttonEvents = anArray; }

        /** 
         * Set the encoded button event objects generated by the classes in the Translate 
         * framework. If the object already contains an array of events objects
         * then they will be deleted.
         * 
         * @param bytes the array of encoded clip events.
         * @param size the number of bytes in the encoded clip event data.
         */
        void setEncodedEvents(byte* bytes, size_t size);

        int lengthInStream(FSOutputStream* aStream);
        void encodeToStream(FSOutputStream* aStream);
        void decodeFromStream(FSInputStream* aStream);

private:
        int buttonType;
        FSVector<FSButton> buttonRecords;
        FSVector<FSButtonEvent> buttonEvents;
        byte* encodedEvents;
        size_t encodedLength;
    };
}

#endif
